#ifndef _SPISERVICE_UTINITIES_UTILKITIES_H_
#define _SPISERVICE_UTINITIES_UTILKITIES_H_

#include <iostream>
#include <type_traits>
#include <array>

template <typename T>
struct is_std_array : std::false_type {};

template <typename T, std::size_t N>
struct is_std_array<std::array<T, N>> : std::true_type {};

class Utility
{
public:
    Utility() = delete;
    ~Utility() = delete;

    static void hex_dump(const void *src, size_t length, size_t line_size, const char *prefix);
    static void hex_dump(const void *src, size_t length, const char *prefix);
    static long long int getTimestampUs();
    static void print_time_consumption(const long long int& last_time_stamp);

    template<typename T>
    static void serialize(const T& input, size_t& index, uint8_t* output);
    template<size_t N>
    static void serialize(const std::array<uint8_t, N>& input, size_t& index, uint8_t* output);

    template<typename T>
    static void unserialize(const uint8_t* input, size_t& index, T& output);
    template<size_t N>
    static void unserialize(const uint8_t* input, size_t& index, std::array<uint8_t, N>& output);

};

template<typename T>
void Utility::serialize(const T& input, size_t& index, uint8_t* output)
{
    auto size = sizeof(T);
    for(size_t i = 1; i <= size; i++)
    {
        output[index++] = input >> (size-i)*8;
    }
}

template<size_t N>
void Utility::serialize(const std::array<uint8_t, N>& input, size_t& index, uint8_t* output)
{
    for(const auto& v : input)
    {
        output[index++] = v;
    }
}

template<typename T>
void Utility::unserialize(const uint8_t* input, size_t& index, T& output)
{
    auto size = sizeof(T);
    for(size_t i = 0; i < size; i++)
    {
        output <<= 8;
        output |= input[index++];
    }
}

template<size_t N>
void Utility::unserialize(const uint8_t* input, size_t& index, std::array<uint8_t, N>& output)
{
    for(auto& v : output)
    {
        v = input[index++];
    }
}

#endif
